
const PENDING = 'pending';
const RESOLVED = 'resolved';
const REJECTED = 'rejected';

function isFunction(f) {
    return typeof f === "function";
}

export default class MyPromise {
    constructor(fn) {
        // 保存Promise状态
        this.state = PENDING;
        // 保存成功回调队列
        this.resolvedCallBack = [];
        this.rejectedCallBack = [];

        let resolve = (value) => {
            if(value instanceof MyPromise) {
                value.then(resolve,reject);
            }
            setTimeout(()=>{
                if(this.state===PENDING) {
                    this.state = RESOLVED
                    this.value = value;
                    this.resolvedCallBack.map(cb => cb(value));
                }
            },0);
        }
        let reject = (err) => {
            setTimeout(()=>{
                if(this.state===PENDING) {
                    this.state = REJECTED;
                    this.reason = err;
                    this.rejectedCallBack.map(cb => cb(err));
                }
            },0);
        }   
        // 执行传入的函数
        try {
            fn(resolve,reject);
        } catch(e) {
            reject(e);
        }
    }
    // then函数
    then(success,fail) {
        success = isFunction(success)?success:val=>val
        fail = isFunction(fail)?fail:err=>{throw err}
        // 返回一个Promise来支持链式调用
        // Promise的值要根据success以及fail的执行情况和返回值来确定
        // 比如success返回的是一个Promise那么后面的then就要等待这个Promise的状态
        // 如果success返回的是一个对象或者函数 那么我们就要根据它上面有没有then来继续调用
        let promise2 = new Promise((resolve,reject)=>{
            if (this.state === RESOLVED) {
                // 调用success函数,并且放在事件队列后边---v8里面的微任务怎么实现的呢？
                setTimeout(()=>{
                    try {
                        let x = success(this.value);
                        this.resolvePromise(promise2,x,resolve,reject);
                    }catch(e) {
                        reject(e);
                    }
                },0);
            }
            if(this.state === REJECTED) {
                setTimeout(()=>{
                    try {
                        let x = fail(this.reason);
                        this.resolvePromise(promise2,x,resolve,reject);
                    }catch(e) {
                        reject(e);
                    }
                },0)
            }
            if(this.state === PENDING) {
                this.resolvedCallBack.push(()=>{
                    try {
                        let x = success(this.value);
                        this.resolvePromise(promise2,x,resolve,reject);
                    }catch(e) {
                        reject(e);
                    }
                })
                this.rejectedCallBack.push(()=>{
                    try {
                        let x = fail(this.reason);
                        this.resolvePromise(promise2,x,resolve,reject);
                    }catch(e) {
                        reject(e);
                    }
                })
            }
        })
        return promise2;
    }
    resolvePromise(promise2,x,resolve,reject) {
        // 不能相同否则会造成循环依赖---比如p1 = p.then(p=>{return p1}); 这时候会造成p1等待p1的局面--卡死了
        if(promise2 === x) {
            return reject(new Error("error"));
        }
        // 如果x是Promise那么继续执行
        if(x instanceof MyPromise) {
            x.then((value)=>{   
                this.resolvePromise(promise2,value,resolve,reject);
            },reject)
        } else {
            // 保证只被调用一次
            let called = false;
            if(x !== null && (typeof x === 'object' || typeof x === 'function')) { // x是对象--如果有then继续判断
                try {
                    let then = x.then;
                    if (typeof then === 'function') { 
                        then.call(x,y=>{
                            if(called)return ;
                            called = true;
                            this.resolvePromise(promise2,y,resolve,reject);
                        },e => {
                            if(called) return ;
                            called = true;
                            reject(e);
                        });
                    }else {
                        resolve(x);
                    }
                }catch(e){
                    if(called)return 
                    called = true;
                    reject(e);
                }
            } else {
                // x是一个普通值
                resolve(x);
            }
        }

    }
}